package com.yueke.gemini.aspect;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import com.yueke.gemini.aspect.annotation.RedisRateLimit;
import com.yueke.gemini.utils.HttpContextUtils;
import com.yueke.gemini.utils.IPUtils;


/**
 * redis限流
 * @author qxw
 * @data 2018年11月1日上午10:32:15
 */
@Aspect
@Component
public class RedisRateLimitAspect {
	 private static final Logger logger = LoggerFactory.getLogger(RedisRateLimitAspect.class);
	 
	 @Autowired
	 private RedisTemplate<String, Serializable> limitRedisTemplate;
	 
	 @Autowired
	 private DefaultRedisScript<Number> redisluaScript;
	 
	 @Pointcut("@annotation(com.yueke.gemini.aspect.annotation.RedisRateLimit)")
	 public void redisPointCut() {
	 }
	 
	 
	 @Around("redisPointCut()")
	    public Object interceptor(ProceedingJoinPoint joinPoint) throws Throwable{
		 //获取注解上的值
	        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
	        Method method = signature.getMethod();
	        Class<?> targetClass = method.getDeclaringClass();
	        RedisRateLimit rateLimit = method.getAnnotation(RedisRateLimit.class);
	        if (rateLimit != null) {
	        	  //获取request
	            HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
	            String ipAddress = IPUtils.getIpAddr(request);
	            StringBuffer stringBuffer = new StringBuffer();
	            stringBuffer.append(ipAddress).append("-")
	                    .append(targetClass.getName()).append("- ")
	                    .append(method.getName()).append("-")
	                    .append(rateLimit.key());

	            List<String> keys = Collections.singletonList(stringBuffer.toString());
	            Number number = limitRedisTemplate.execute(redisluaScript, keys, rateLimit.count(), rateLimit.time());

	            if (number != null && number.intValue() != 0 && number.intValue() <= rateLimit.count()) {
	                logger.info("限流时间段内访问第：{} 次", number.toString());
	                return joinPoint.proceed();
	            }
	        } else {
	            return joinPoint.proceed();
	        }
	        throw new RuntimeException("已经到设置限流次数");
	    }

	  
}
